package com.naiterui.ehp.bs.recommend.service.impl;

import static com.naiterui.ehp.bp.utils.date.DateUtil.DAY_TIME_FORMAT;

import java.util.Date;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.naiterui.ehp.bp.bo.recommend.param.RebuyNoticeParamBO;
import com.naiterui.ehp.bp.support.exception.BusinessException;
import com.naiterui.ehp.bp.utils.date.DateUtil;
import com.naiterui.ehp.bp.utils.lang.ConfigUtil;
import com.naiterui.ehp.bs.recommend.bean.MedicationRecom;
import com.naiterui.ehp.bs.recommend.bean.mongo.PatientRebuyNotice;
import com.naiterui.ehp.bs.recommend.dao.mongo.RebuyNoticeDao;
import com.naiterui.ehp.bs.recommend.remote.IRecommendRemoter;
import com.naiterui.ehp.bs.recommend.repository.mysql.IMedicationRecomRepository;
import com.naiterui.ehp.bs.recommend.service.IRebuyNoticeService;
import com.naiterui.ehp.bs.recommend.service.IRecomDetailService;
import com.naiterui.ehp.bs.recommend.util.Constants;
import com.naiterui.ehp.bs.recommend.vo.RecomDrugCycleVO;

/**
 * 复购提醒业务逻辑相关实现层
 *
 * @since 2.19
 */
@Service
public class RebuyNoticeServiceImpl implements IRebuyNoticeService {
    private static Logger LOGGER = LoggerFactory.getLogger(RebuyNoticeServiceImpl.class);

    @Autowired
    private IRecomDetailService recomDetailService;

    @Autowired
    private RebuyNoticeDao rebuyNoticeDao;

    @Autowired
    private IMedicationRecomRepository medicationRecomRepository;

    @Autowired
    private IRecommendRemoter remoter;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveRebuyNotice(Long patientId, Long baseOrderId, RebuyNoticeParamBO rebuyNoticeParamBO) throws BusinessException {
        // 判断当前患者是否存在未发送的复购提醒,如果存在则删除
        this.rebuyNoticeDao.removeUnSendRebuyNotice(patientId);
        // 计算多个处方的最长用药周期
        RecomDrugCycleVO recomDrugCycleVO = this.recomDetailService.getLongestRecommend(rebuyNoticeParamBO);
        // 根据用药周期计算提醒时间(当前回调时间 + 用药周期 + 14天)
        if (recomDrugCycleVO != null && recomDrugCycleVO.getDrugCycle() != null) {
            Date drugEndTime = DateUtil.addDays(new Date(), recomDrugCycleVO.getDrugCycle());
            LOGGER.info("计算出用药周期为 {} 天，用药结束日期为：{} ", recomDrugCycleVO.getDrugCycle()
                    , DateUtil.formatDate(drugEndTime, DateUtil.DATE_FORMAT_CN));
            // 获取推荐医生信息
            MedicationRecom medicationRecom = this.medicationRecomRepository.get(recomDrugCycleVO.getRecommendId());

            recomDrugCycleVO.setBaseOrderId(baseOrderId);
            recomDrugCycleVO.setNowDate(new Date());
            recomDrugCycleVO.setPatientId(patientId);
            recomDrugCycleVO.setDoctorId(medicationRecom.getDoctorId());
            //生成用药周期前三天提醒-验证并保持复购提醒 TODO:config配置
            Integer fiveDay = ConfigUtil.getInt("rebuy.notice.time.five");
            if (recomDrugCycleVO.getDrugCycle() > fiveDay) {
                this.valRevisitNotice(recomDrugCycleVO, ConfigUtil.getInt("rebuy.notice.befor.time"));
            }
            //生成用药周期14天后提醒-验证并保持复购提醒
            this.valRevisitNotice(recomDrugCycleVO, ConfigUtil.getInt("rebuy.notice.overtime"));
        } else {
            LOGGER.warn("购买药品无用药周期，不生成复购提醒记录。rebuyNoticeParamBO: {}", rebuyNoticeParamBO);
        }
    }

    /**
     * @param recomDrugCycleVO 复购周期
     *
     * @return void
     *
     * @throws
     * @method valRevisitNotice
     * @author chengqiang
     * @description 验证复购通知时间内是否存在医嘱提醒
     * @date 2018/11/20 11:19
     **/
    private void valRevisitNotice(RecomDrugCycleVO recomDrugCycleVO, Integer noticeDay) throws BusinessException {
        Long doctorId = recomDrugCycleVO.getDoctorId();
        Long patientId = recomDrugCycleVO.getPatientId();
        //根据通知天生成复购提醒时间
        Integer afterNoticeDay = noticeDay + recomDrugCycleVO.getDrugCycle();
        Date noticeDate = DateUtil.addDays(recomDrugCycleVO.getNowDate(), afterNoticeDay);
        // 判断提醒的前3天后15天是否有医嘱提醒,没有则生成提醒记录
        Date startDate = DateUtil.minusDays(noticeDate, ConfigUtil.getInt("rebuy.notice.revisit.start"));
        Date endDate = DateUtil.addDays(noticeDate, ConfigUtil.getInt("rebuy.notice.revisit.end"));

        boolean containVisitNotice = this.remoter.checkRevisitNotice(doctorId, patientId, startDate, endDate);
        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug(
                    "复购提醒校验是否存在医嘱提醒：recommendId: {}, drugCycle: {},noticeDate: {}, doctorId: {}, patientId: {}, " +
                            "startDate: {}, endDate: {},containVisitNotice:{}",
                    recomDrugCycleVO.getRecommendId(), recomDrugCycleVO.getDrugCycle(),
                    DateUtil.formatDate(noticeDate, DateUtil.DATE_TIME_FORMAT), doctorId, patientId,
                    DateUtil.formatDate(startDate, DateUtil.DATE_TIME_FORMAT), DateUtil.formatDate(endDate, DateUtil.DATE_TIME_FORMAT),
                    containVisitNotice);
        }
        //不存在医嘱，保存复购提醒记录
        if (!containVisitNotice) {
            PatientRebuyNotice patientRebuyNotice = new PatientRebuyNotice();
            patientRebuyNotice.setPatientId(patientId);
            patientRebuyNotice.setDoctorId(doctorId);
            patientRebuyNotice.setBaseOrderId(recomDrugCycleVO.getBaseOrderId());
            patientRebuyNotice.setRecommendId(recomDrugCycleVO.getRecommendId());
            patientRebuyNotice.setSkuId(recomDrugCycleVO.getSkuId());
            patientRebuyNotice.setNoticeTime(DateUtil.formatDate(noticeDate, DateUtil.DAY_TIME_FORMAT));
            patientRebuyNotice.setStatus(Constants.REBUY_NOTICE_STATUS_UNSEND);
            patientRebuyNotice.setCreatedAt(new Date());
            patientRebuyNotice.setCreatedBy("patient:" + patientId);
            patientRebuyNotice.setNoticeType(PatientRebuyNotice.NOTICE_TYPE_LATER_FOURTEEN_DAY);
            //设置3天前推送类型
            int beforThreeDay = ConfigUtil.getInt("rebuy.notice.befor.time");
            if (beforThreeDay == noticeDay) {
                patientRebuyNotice.setNoticeType(PatientRebuyNotice.NOTICE_TYPE_BEFOR_TREE_DAY);
            }
            this.rebuyNoticeDao.saveRebuyNotice(patientRebuyNotice);
        } else {
            LOGGER.info("存在医嘱提醒，不生成复购提醒...订单：" + recomDrugCycleVO.getBaseOrderId() + "，复购提醒时间：" + noticeDate);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeUnsendNotice(Long patientId, String visitTime) throws BusinessException {
        String startTime = null;
        String endTime = null;
        if (StringUtils.isNotEmpty(visitTime)) {
            Date visitTimeStamp = DateUtil.parseStrToCustomPatternDate(visitTime, DateUtil.DAY_TIME_FORMAT);
            startTime = DateUtil.formatDate(DateUtil.minusDays(visitTimeStamp, ConfigUtil.getInt("rebuy.notice.revisit.end")),
                    DAY_TIME_FORMAT);
            endTime = DateUtil.formatDate(DateUtil.addDays(visitTimeStamp, ConfigUtil.getInt("rebuy.notice.revisit.start")),
                    DAY_TIME_FORMAT);
        }
        LOGGER.info("根据医嘱时间删除复购提醒，patientId：{}，startTime：{}，endTime：{}，", patientId, startTime, endTime);
        this.rebuyNoticeDao.removeUnSendNoticeWithTime(patientId, startTime, endTime);

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeByOrderId(Long baseOrderId) throws BusinessException {
        this.rebuyNoticeDao.removeUnSendNoticeWithOrderId(baseOrderId);
    }

}
